package cn.sx.guoxd.springboot.util;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@SuppressWarnings({"rawtypes", "unchecked"})
@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class}),
})
public class MyInterceptor implements Interceptor {
    //private Field additionalParametersField;
    private static final List<ResultMapping> EMPTY_RESULTMAPPING = new ArrayList<ResultMapping>(0);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args =  invocation.getArgs();
        MappedStatement ms = (MappedStatement)args[0];
        Object parameterObject = args[1];
        RowBounds rowBounds = (RowBounds)args[2];
        //需要分页
        ResultHandler resultHandler = (ResultHandler)args[3];
        Executor executor = (Executor)invocation.getTarget();
        BoundSql boundSql = ms.getBoundSql(parameterObject);

        //Map<String,Object> additionalParameters = (Map<String,Object>)additionalParametersField.get(boundSql);
        //进行count查询
        MappedStatement countMs = newMappedStatement(ms, Long.class);
        CacheKey countKey= executor.createCacheKey(countMs, parameterObject, RowBounds.DEFAULT, boundSql);

        String countSql = "select count(0) from tb_user";
        BoundSql countBoundSql = new BoundSql(ms.getConfiguration(),countSql,boundSql.getParameterMappings(),parameterObject);

        Object countResultList = executor.query(countMs, parameterObject,RowBounds.DEFAULT, resultHandler,countKey, countBoundSql);
        Long count = (Long)((List)countResultList).get(0);

        ((PageRowBounds)rowBounds).setTotal(count);

        //分页查询
        CacheKey pageKey  = executor.createCacheKey(ms,parameterObject,rowBounds,boundSql);
        String pageSql = "SELECT\n" +
                "        t1.id,\n" +
                "        t1.`name`,\n" +
                "        t1.birthday,\n" +
                "        t1.lab_age,\n" +
                "        t1.lab_name,\n" +
                "        t1.lab_duty,\n" +
                "        t2.number AS drv_number,\n" +
                "        t2.driving_type_code AS drv_type_code,\n" +
                "        t2.driving_type_name AS drv_type_name\n" +
                "        FROM\n" +
                "        tb_user AS t1\n" +
                "        LEFT JOIN tb_driving_license AS t2 ON t1.id = t2.id Limit 0,2";
        BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(),pageSql,boundSql.getParameterMappings(),parameterObject);
        List resultList = executor.query(ms, parameterObject,RowBounds.DEFAULT, resultHandler,pageKey,pageBoundSql);



        return resultList;
    }

    public MappedStatement newMappedStatement(MappedStatement ms, Class<?> resultType){
        MappedStatement.Builder builder = new MappedStatement.Builder(
                ms.getConfiguration(),
                ms.getId()+"_Count",
                ms.getSqlSource(),
                ms.getSqlCommandType()
        );
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {
            StringBuilder keyProperties = new StringBuilder();
            for (String keyProperty:ms.getKeyProperties()) {
                keyProperties.append(keyProperty).append(",");
            }
            keyProperties.delete(keyProperties.length()-1, keyProperties.length());
            builder.keyProperty(keyProperties.toString());
        }
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());

        List<ResultMap> resultMaps = new ArrayList<>();
        ResultMap resultMap = new ResultMap.Builder(
                ms.getConfiguration(),
                ms.getId(),
                resultType,
                EMPTY_RESULTMAPPING
        ).build();
        resultMaps.add(resultMap);
        builder.resultMaps(resultMaps);
        builder.resultSetType(ms.getResultSetType());
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());
        return builder.build();
    }
}
